<script setup lang="ts">
import { ref, watch, onMounted, onUnmounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { Script } from '../entity'
import type { Project } from '../entity'
import * as scriptApi from '../api/script'
import { QuestionFilled } from '@element-plus/icons-vue'

const props = defineProps<{
  projectId: string
  project: Project
}>()

// 脚本列表
const scriptList = ref<Script[]>([])

// 脚本表单
const scriptDialogVisible = ref(false)
const scriptForm = ref<Partial<Script>>({})

// 执行结果对话框
const executeDialogVisible = ref(false)
const executeResult = ref('')
const currentScript = ref<Script | null>(null)

// 执行状态管理
interface ExecutionStatus {
  scriptId: string
  status: 'running' | 'completed' | 'error'
  startTime: Date
  endTime?: Date
  exitCode: number | undefined
  output: string
}

const executionStatuses = ref<Map<string, ExecutionStatus>>(new Map())
const currentProcess = ref<any>(null)

// 加载脚本列表
const loadScripts = async () => {
  try {
    scriptList.value = await scriptApi.getProjectScripts(props.projectId)
  } catch (error) {
    console.error('加载脚本列表失败:', error)
    ElMessage.error('加载脚本列表失败')
  }
}

// 监听脚本类型变化，自动更新文件扩展名
const updateFilename = () => {
  if (scriptForm.value.filename) {
    // 移除旧的扩展名（如果有）
    const baseName = scriptForm.value.filename.replace(/\.[^/.]+$/, '')
    // 添加新的扩展名
    scriptForm.value.filename = `${baseName}.${getFileExtension(scriptForm.value.scriptType)}`
  }
}

// 监听脚本类型变化
watch(() => scriptForm.value.scriptType, (newType) => {
  if (newType) {
    updateFilename()
  }
})

// 脚本相关操作
const handleAddScript = () => {
  scriptForm.value = {
    name: '',           // 添加默认值
    command: '',        // 添加默认值
    content: '',        // 添加默认值
    description: '',    // 添加默认值
    scriptType: 'shell',  // 默认选择 shell 类型
    filename: `script.${getFileExtension('shell')}`  // 默认文件名
  }
  scriptDialogVisible.value = true
}

const handleEditScript = (script: Script) => {
  scriptForm.value = { ...script }
  // 确保文件名与脚本类型匹配
  updateFilename()
  scriptDialogVisible.value = true
}

const handleDeleteScript = async (script: Script) => {
  try {
    await ElMessageBox.confirm('确除脚本吗？', '提示', {
      type: 'warning'
    })
    await scriptApi.removeScript(script.id)
    ElMessage.success('删除成功')
    loadScripts()
  } catch (error) {
    if (error !== 'cancel') {
      console.error('删除失败:', error)
      ElMessage.error('删除失败')
    }
  }
}

const handleScriptSubmit = async () => {
  try {
    // 表单验证
    if (!scriptForm.value.name || !scriptForm.value.command || 
        !scriptForm.value.scriptType || !scriptForm.value.filename) {
      ElMessage.warning('请填写必填项')
      return
    }

    if (scriptForm.value.id) {
      await scriptApi.updateScript({
        id: scriptForm.value.id,
        name: scriptForm.value.name,
        description: scriptForm.value.description || '',
        content: scriptForm.value.content || '',
        command: scriptForm.value.command,
        scriptType: scriptForm.value.scriptType,
        filename: scriptForm.value.filename
      })
    } else {
      await scriptApi.addScript(props.projectId, {
        name: scriptForm.value.name,
        description: scriptForm.value.description || '',
        content: scriptForm.value.content || '',
        command: scriptForm.value.command,
        scriptType: scriptForm.value.scriptType,
        filename: scriptForm.value.filename
      })
    }

    ElMessage.success('保存成功')
    scriptDialogVisible.value = false
    loadScripts()  // 重新加载脚本列表
  } catch (error) {
    console.error('保存失败:', error)
    ElMessage.error('保存失败')
  }
}

// 创建临时脚本
const createTempScript = async (script: Script): Promise<string> => {
  const projectPath = props.project?.path
  if (!script.content || !script.filename || !projectPath) {
    throw new Error('脚本内容、文件名或项目路径不能为空')
  }

  const tempDir = await window.path.join(projectPath, '.temp')
  if (typeof tempDir !== 'string') {
    throw new Error('无法创建临时目录路径')
  }

  const scriptPath = await window.path.join(tempDir, script.filename)
  if (typeof scriptPath !== 'string') {
    throw new Error('无法创建脚本路径')
  }
  
  // 确保临时目录存在
  if (!await window.fs.existsSync(tempDir)) {
    await window.fs.mkdir(tempDir)
  }
  
  // 写入脚本内容
  await window.fs.writeFile(scriptPath, script.content)
  
  // 在 Unix/Mac 系统上设置执行权限
  if (!window.platform.isWindows) {
    await window.childProcess.exec(`chmod +x "${scriptPath}"`, {
      cwd: projectPath
    })
  }
  
  return scriptPath
}

// 执行脚本
const handleExecute = async (script: Script): Promise<void> => {
  const projectPath = props.project?.path
  if (!script.id || !script.command || !script.name || !projectPath) {
    ElMessage.error('脚本信息不完整')
    return
  }

  try {
    // 如果已经在运行，先停止
    if (currentProcess.value) {
      await stopExecution()
    }

    // 创建执行状态
    const status: ExecutionStatus = {
      scriptId: script.id,
      status: 'running',
      startTime: new Date(),
      output: '',
      exitCode: undefined
    }
    executionStatuses.value.set(script.id, status)
    
    // 创建临时文件
    const scriptPath = await createTempScript(script)
    
    // 添加初始日志
    status.output += `[INFO] 开始执行脚本: ${script.name}\n`
    status.output += `[INFO] 工作目录: ${projectPath}\n`
    status.output += `[INFO] 命令: ${script.command}\n\n`
    executionStatuses.value.set(script.id, { ...status })

    // 构建执行命令
    const command = window.platform.isWindows 
      ? script.command 
      : `cd "${projectPath}" && bash "${scriptPath}"`

    // 执行命令并等待结果
    const result = await window.childProcess.exec(command, {
      cwd: projectPath,
      onOutput: (output) => {
        const str = output.data
        status.output += str
        executionStatuses.value.set(script.id, { ...status })
        if (currentScript.value?.id === script.id) {
          executeResult.value = status.output
        }
      }
    })

    // 添加执行结果日志
    status.output += `\n[INFO] 脚本执行完成\n`
    status.output += `[INFO] 退出码: ${result.code}\n`
    if (result.code !== 0) {
      status.output += `[ERROR] 脚本执行失败\n`
    }
    
    // 更新执行状态
    status.status = result.code === 0 ? 'completed' : 'error'
    status.endTime = new Date()
    status.exitCode = result.code ?? 1  // 如果 code 为 null，则使用 1
    executionStatuses.value.set(script.id, { ...status })
    
    // 清理临时文件
    await cleanup(scriptPath)
    
    currentProcess.value = null
    
  } catch (error) {
    console.error('执行脚本���败:', error)
    const status = executionStatuses.value.get(script.id)
    if (status) {
      status.status = 'error'
      status.endTime = new Date()
      status.exitCode = 1
      status.output += `\n[ERROR] 执行失败: ${error instanceof Error ? error.message : String(error)}\n`
      executionStatuses.value.set(script.id, { ...status })
      if (currentScript.value?.id === script.id) {
        executeResult.value = status.output
      }
    }
    currentProcess.value = null
  }
}

// 停止执行
const stopExecution = async () => {
  if (currentProcess.value) {
    try {
      if (window.platform.isWindows) {
        await window.childProcess.exec('taskkill /F /IM script.bat')
      } else {
        await window.childProcess.exec('pkill -f script.sh')
      }
    } catch (error) {
      console.error('停止脚本执行失败:', error)
    }
    currentProcess.value = null
  }
}

// 清理临时文件
const cleanup = async (scriptPath: string): Promise<void> => {
  const projectPath = props.project?.path
  if (!projectPath) {
    console.error('项目路径不存在')
    return
  }

  try {
    if (await window.fs.existsSync(scriptPath)) {
      await window.fs.unlink(scriptPath)
    }
    const tempDir = await window.path.join(projectPath, '.temp')
    if (typeof tempDir === 'string' && await window.fs.existsSync(tempDir)) {
      await window.fs.rmdir(tempDir)
    }
  } catch (error) {
    console.error('清理临时文件失败:', error)
  }
}

// 查看执行结果
const handleViewResult = (script: Script) => {
  currentScript.value = script
  const status = executionStatuses.value.get(script.id)
  if (status) {
    executeResult.value = status.output
  } else {
    executeResult.value = '暂无执行结果'
  }
  executeDialogVisible.value = true
}

// 格式化执行状态
const formatExecutionStatus = (status: ExecutionStatus | undefined) => {
  if (!status) return '未执行'
  if (status.status === 'running') return '执行中...'
  return status.status === 'completed' ? '执行完成' : '执行出错'
}

// 格式化执行时间
const formatExecutionTime = (status: ExecutionStatus | undefined) => {
  if (!status || !status.startTime) return '--'
  const start = new Date(status.startTime)
  const end = status.status === 'running' ? new Date() : (status.endTime ? new Date(status.endTime) : new Date())
  const diff = end.getTime() - start.getTime()
  return `${(diff / 1000).toFixed(1)}s`
}

// 在组件卸载时清理
onUnmounted(async () => {
  await stopExecution()
})

// 初始化加载
onMounted(() => {
  loadScripts()
})

// 暴露方法给父组件
defineExpose({
  loadScripts
})

// 获取文件扩展名
const getFileExtension = (type?: string) => {
  switch (type) {
    case 'shell':
      return window.platform.isWindows ? 'bat' : 'sh'
    case 'python':
      return 'py'
    case 'nodejs':
      return 'js'
    default:
      return ''
  }
}

// 获取行数
const getLineCount = (content?: string) => {
  if (!content) return 1
  return content.split('\n').length
}

// 获取命令提示
const getCommandTip = (type?: string, filename?: string) => {
  if (!type || !filename) return ''
  
  const extension = getFileExtension(type)
  switch (type) {
    case 'shell':
      return window.platform.isWindows 
        ? `${filename}.${extension}` 
        : `bash ${filename}.${extension}`
    case 'python':
      return `python ${filename}.${extension}`
    case 'nodejs':
      return `node ${filename}.${extension}`
    default:
      return ''
  }
}

// 监听脚本类型和文件名变化，自动更新命令提示
watch([() => scriptForm.value.scriptType, () => scriptForm.value.filename], () => {
  if (!scriptForm.value.command) {
    scriptForm.value.command = getCommandTip(
      scriptForm.value.scriptType,
      scriptForm.value.filename?.replace(/\.[^/.]+$/, '')  // 移除已有的扩展名
    )
  }
})
</script>

<template>
  <div class="script-config">
    <div class="mb-4">
      <el-button type="primary" size="small" @click="handleAddScript">添加脚本</el-button>
    </div>

    <el-table :data="scriptList" border>
      <el-table-column label="脚本名称" prop="name" />
      <el-table-column label="脚本类型" prop="scriptType">
        <template #default="{ row }">
          {{ row.scriptType === 'shell' ? 'Shell 脚本' : 
             row.scriptType === 'python' ? 'Python 脚本' : 
             row.scriptType === 'nodejs' ? 'Node.js 脚本' : '' }}
        </template>
      </el-table-column>
      <el-table-column label="文件名" prop="filename" />
      <el-table-column label="命令" prop="command" show-overflow-tooltip />
      <el-table-column label="描述" prop="description" show-overflow-tooltip />
      <el-table-column label="执行状态" width="180">
        <template #default="{ row }">
          <div class="execution-status">
            <el-tag
              :type="executionStatuses.get(row.id)?.status === 'running' ? 'warning' :
                     executionStatuses.get(row.id)?.status === 'completed' ? 'success' :
                     executionStatuses.get(row.id)?.status === 'error' ? 'danger' : 'info'"
            >
              {{ formatExecutionStatus(executionStatuses.get(row.id)) }}
            </el-tag>
            <span class="execution-time">
              {{ formatExecutionTime(executionStatuses.get(row.id)) }}
            </span>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="操作" width="320">
        <template #default="{ row }">
          <el-button link type="primary" size="small" @click="handleEditScript(row)">
            编辑
          </el-button>
          <el-button link type="success" size="small" @click="handleExecute(row)">
            执行
          </el-button>
          <el-button 
            link 
            type="info" 
            size="small" 
            @click="handleViewResult(row)"
            :disabled="!executionStatuses.get(row.id)"
          >
            查看结果
          </el-button>
          <el-button link type="danger" size="small" @click="handleDeleteScript(row)">
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 脚本配置对话框 -->
    <el-dialog
      v-model="scriptDialogVisible"
      :title="scriptForm.id ? '编辑脚本' : '新增脚本'"
      width="800px"
      destroy-on-close
    >
      <el-form :model="scriptForm" label-width="100px">
        <el-form-item label="脚本名称" required>
          <el-input v-model="scriptForm.name" placeholder="输入脚本名称" />
        </el-form-item>
        <el-form-item label="脚本类型" required>
          <el-select v-model="scriptForm.scriptType" placeholder="请选择脚本类型">
            <el-option label="Shell 脚本" value="shell" />
            <el-option label="Python 脚本" value="python" />
            <el-option label="Node.js 脚本" value="nodejs" />
          </el-select>
        </el-form-item>
        <el-form-item label="文件名称" required>
          <el-input v-model="scriptForm.filename" placeholder="请输入文件名">
            <template #append>
              <span class="extension">.{{ getFileExtension(scriptForm.scriptType) }}</span>
            </template>
          </el-input>
        </el-form-item>
        <el-form-item label="行命令" required>
          <el-input 
            v-model="scriptForm.command" 
            placeholder="请输入执行命令"
          >
            <template #append>
              <el-tooltip 
                :content="getCommandTip(scriptForm.scriptType, scriptForm.filename?.replace(/\.[^/.]+$/, ''))"
                placement="top"
              >
                <el-icon><QuestionFilled /></el-icon>
              </el-tooltip>
            </template>
          </el-input>
          <template #hint>
            <span class="command-hint">
              提示：根据脚本类型，可以使用
              <code>{{ getCommandTip(scriptForm.scriptType, scriptForm.filename?.replace(/\.[^/.]+$/, '')) }}</code>
            </span>
          </template>
        </el-form-item>
        <el-form-item label="脚本内容">
          <div class="editor-container">
            <div class="line-numbers">
              <div v-for="i in getLineCount(scriptForm.content)" :key="i" class="line-number">
                {{ i }}
              </div>
            </div>
            <el-input
              v-model="scriptForm.content"
              type="textarea"
              :autosize="{ minRows: 12, maxRows: 20 }"
              placeholder="请输入脚本内容，支持 Shell/Batch 脚本"
              class="script-content"
            />
          </div>
        </el-form-item>
        <el-form-item label="描述">
          <el-input
            v-model="scriptForm.description"
            type="textarea"
            :rows="3"
            placeholder="请输入描述"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="scriptDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleScriptSubmit">确定</el-button>
      </template>
    </el-dialog>

    <!-- 执行结果对话框 -->
    <el-dialog
      v-model="executeDialogVisible"
      :title="`执行结果: ${currentScript?.name || ''}`"
      width="800px"
      destroy-on-close
    >
      <div class="execute-dialog-content">
        <el-alert
          v-if="currentScript"
          :title="currentScript.command"
          type="info"
          class="mb-4"
        />
        <div 
          class="execute-result"
          v-html="executeResult"
        />
      </div>
      <template #footer>
        <el-button @click="executeDialogVisible = false">关闭</el-button>
        <el-button 
          type="primary" 
          @click="() => currentScript && handleExecute(currentScript)"
          :loading="executionStatuses.get(currentScript?.id)?.status === 'running'"
        >
          重新执行
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped lang="scss">
.mb-4 {
  margin-bottom: 16px;
}

.execute-dialog-content {
  min-height: 200px;
}

.execute-result {
  font-family: 'Consolas', monospace;
  padding: 12px;
  line-height: 1.6;
  white-space: pre-wrap;
  background-color: var(--el-bg-color-page);
  border: 1px solid var(--el-border-color);
  border-radius: 4px;
  height: 400px;
  overflow-y: auto;

  :deep(span) {
    font-family: inherit;
  }
}

.editor-container {
  display: flex;
  width: 100%;
  border: 1px solid var(--el-border-color);
  border-radius: 4px;
  overflow: hidden;
  background-color: var(--el-bg-color);
}

.line-numbers {
  padding: 8px 0;
  background-color: var(--el-fill-color-darker);
  border-right: 1px solid var(--el-border-color-darker);
  text-align: right;
  color: var(--el-text-color-secondary);
  user-select: none;
}

.line-number {
  padding: 0 8px;
  font-family: 'Consolas', monospace;
  font-size: 13px;
  line-height: 21px;
  height: 21px;
}

.script-content {
  flex: 1;
  
  :deep(.el-textarea__inner) {
    border: none;
    padding: 8px 12px;
    height: 100%;
    font-family: 'Consolas', monospace;
    font-size: 13px;
    line-height: 21px;
    background-color: var(--el-bg-color);
    resize: none;
    
    &:focus {
      box-shadow: none;
    }
  }

  /* 隐藏默认边框 */
  :deep(.el-textarea__inner:focus) {
    border-color: transparent;
    box-shadow: none;
  }
}

/* 调整对话框度 */
:deep(.el-dialog) {
  .el-dialog__body {
    padding: 20px 20px;
  }

  .el-form-item {
    margin-bottom: 18px;
    
    &:last-child {
      margin-bottom: 0;
    }
  }
}

/* 调整表单布局 */
:deep(.el-form-item__content) {
  flex: 1;
  min-width: 0;  /* 防止内容溢出 */
}

/* 移除 word-limit 显示 */
:deep(.el-input__count) {
  display: none;
}

.extension {
  color: var(--el-text-color-secondary);
  padding: 0 4px;
}

.command-hint {
  color: var(--el-text-color-secondary);
  font-size: 12px;
  
  code {
    background-color: var(--el-fill-color-light);
    padding: 2px 4px;
    border-radius: 3px;
    margin: 0 2px;
    font-family: 'Consolas', monospace;
  }
}

.execution-status {
  display: flex;
  align-items: center;
  gap: 8px;

  .execution-time {
    color: var(--el-text-color-secondary);
    font-size: 12px;
  }
}
</style>
